package com.qinglei.recoup.longconn.handler;


import com.qinglei.recoup.longconn.constant.LongConnConstant;
import com.qinglei.recoup.longconn.utils.CommonUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.DecoderException;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteOrder;
import java.util.Arrays;

@Slf4j
public class HeaderDecoder extends LengthFieldBasedFrameDecoder {
    public HeaderDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        return super.decode(ctx, in);
    }

    @Override
    protected long getUnadjustedFrameLength(ByteBuf buf, int offset, int length, ByteOrder order) {
//        buf = buf.order(order);
        if (!checkHeader(buf)) {
            byte[] data = new byte[buf.writerIndex()];
            buf.getBytes(0, data);
            log.info(" Receive bad data: " + CommonUtils.bytesToHexString(data));
            throw new DecoderException("Header is error, ByteBuf be modified!");
        }
        long frameLength;
        switch (length) {
            case 1:
                frameLength = buf.getUnsignedByte(offset);
                break;
            case 2:
                frameLength = buf.getUnsignedShort(offset);
                break;
            case 3:
                frameLength = buf.getUnsignedMedium(offset);
                break;
            case 4:
                frameLength = buf.getUnsignedInt(offset);
                break;
            case 8:
                frameLength = buf.getLong(offset);
                break;
            default:
                throw new DecoderException(
                        "unsupported lengthFieldLength: " + length + " (expected: 1, 2, 3, 4, or 8)");
        }
        return frameLength;
    }

    /**
     * 检查有信息
     *
     * @param in
     */
    private boolean checkHeader(ByteBuf in) {
        boolean flag = true;
        int writer = in.writerIndex();
        byte[] header = new byte[2];
        int beginIndex = in.readerIndex();
        in.getBytes(beginIndex, header);

        while (!Arrays.equals(header, LongConnConstant.PROTOCOL_HEADER) && beginIndex < writer) {
            beginIndex++;
            in.readerIndex(beginIndex);
            in.getBytes(beginIndex, header);
        }
        if (!Arrays.equals(header, LongConnConstant.PROTOCOL_HEADER)) {
            flag = false;
        }
        return flag;
    }

}
